Example analysis in R
The estrogen dataset
The experiment we will analyse is made-up of eight Affymetrix HGU95Av2 GeneChips. The aim of the experiment is briefly described below (excerpt taken from the factDesign package vignette).
“The investigators in this experiment were interested in the effect of estrogen on the genes in ER+ breast cancer cells over time. After serum starvation of all eight samples, they exposed four samples to estrogen, and then measured mRNA transcript abundance after 10 hours for two samples and 48 hours for the other two. They left the remaining four samples untreated, and measured mRNA transcript abundance at 10 hours for two samples, and 48 hours for the other two. Since there are two factors in this experiment (estrogen and time), each at two levels (present or absent, 10 hours or 48 hours), this experiment is said to have a 2 × 2 factorial design.”
The data for this section are described in the estrogen data package in Bioconductor
The cel files for the example experiement are stored in the estrogen directory
The first stage is to read the targets file. In Bioconductor we often use a targets file to define the files corresponding to the raw data for the experiment and which sample groups they belong to. Such a file can be created in a spreadsheet, or text editor, and usually saved as a tab-delimited file. We can have as many columns in the file as we see fit, and one row for each hybridisation. The sample group information is propogated through the analysis and incorporated in the quality assessment and eventually differential expression. We refer to this as the “phenotype data” for the experiment, or sometimes the “metadata”.
Packages and data
If you did not install the affy Bioconductor package, you will need to do so now:-
source("http://www.bioconductor.org/biocLite.R")
biocLite("affy")
The data for the practical can be found in the course zip file
library(affy)
targetsFile <- "estrogen/estrogen.txt"
targetsFile
[1] "estrogen/estrogen.txt"
pd <- read.AnnotatedDataFrame(targetsFile,header=TRUE,sep="",row.names=1)
pData(pd)
As .cel files are not a typical file format, we cannot use the standard R functions such as read.delim, read.csv and read.table. The function to import the data is ReadAffy from the affy package.
raw <-ReadAffy(celfile.path = "estrogen", filenames=rownames(pData(pd)),phenoData = pd)
raw
replacing previous import ‘AnnotationDbi::tail’ by ‘utils::tail’ when loading ‘hgu95av2cdf’replacing previous import ‘AnnotationDbi::head’ by ‘utils::head’ when loading ‘hgu95av2cdf’
AffyBatch object
size of arrays=640x640 features (19 kb)
cdf=HG_U95Av2 (12625 affyids)
number of samples=8
number of genes=12625
annotation=hgu95av2
notes=
What type of Affy array is this How many features? How many samples?
Diagnostic plots
As with other high-throughput technologies, quality assessment is an important part of the analysis process. Data quality can be checked using various diagnostic plots.
The first diagnostic plot we will meet is the “boxplot”, which is a commonly-used plot in data analysis for comparing data distributions. The exact definition of how is boxplot is drawn can vary, the definitions always hold;
- The bottom of the box is the first quartile; the 25th percentile
- The top of the box is the third quartile; the 75th percentile
- The median is represented by a horizontal line
- The inter-quartile range (IQR) is the difference between the 75th and 25th percentiles
Here, we draw a boxplot to compare two distributions; x with a mean of 0 and standard deviation of 1, and y with a mean of 2 and standard deviation of 4.
x <- rnorm(100)
y <- rnorm(100, mean = 2,sd=4)
boxplot(x,y)

It is also common to draw whiskers that extend to 1.5 X the IQR from the lower and upper quartile. Any points outside this range can be represented by a dot.
In Bioconductor, you will usually find that package authors have created shortcuts to allow complicated data types to be visualised with common functions. For instance, if we want to construct a boxplot from our raw Affymetrix data it would be quite a daunting task for the novice to extract the revelant information from the object. Instead, we can use functions that we are familiar with such as boxplot. The plot can also be customised in ways that we are familiar with such as changing the color (the col argument) and label orientation (las=2 to make labels perpendicular to the axis)
boxplot(raw,col="red",las=2)

What do you notice from this plot?
Perfect-Match and Mismatch probes
With the short DNA sequences used for microarray hybridisation, there is the possibility for the sequence designed to not be specific-enough and hybridise to many regions of the genome. Affymetrix attempt to resolve this issue by having a mismatch sequence corresponding to each probe. Ideally, the subtracting the mismatch from the corresponding perfect match( \(PM - MM\)) should yield a background-corrected, and more-reliable, signal.
Generate histograms of the PM and MM intensities from the first array. Do you notice any difference in the signal distribution of the PMs and MMs?
par(mfrow=c(2,1))
hist(log2(pm(raw[,1])),breaks=100,col="steelblue",main="PM",xlim=c(4,14))
hist(log2(mm(raw[,1])),breaks=100,col="steelblue",main="MM",xlim=c(4,14))

M-A plots are a useful way of comparing the red and green channels from a two-colour microarray. For Affymetrix data, which is a single-channel technology, M and A values can be calculated using the intensities from a pair of chips. We would typically produce a plot using samples from the same biological group, where we would not expect to observe much difference in intensity for a given gene.
i.e. if X\(_i\) is the intensity of a given probe from chip \(i\) and X\(_j\) is the intensity for the same probe on chip \(j\), then \(A = 1/2 (log_2(X_i) + log_2(X_j))\) and \(M = log_2(X_i) − log_2(X_j)\) . In this experiment, there are 8 GeneChips, which gives 28 distinct pair-wise comparisons between arrays. We will focus on a subset of these below.
mva.pairs(pm(raw)[,1:4],plot.method="smoothScatter")

mva.pairs(pm(raw)[,5:8],plot.method="smoothScatter")

Based on all the plots you have generated, what would you conclude about the overall quality of this experiment? ******
Probe-level Linear Models
Probe-level Linear Models (PLMs) can be used as an additional tool to assess relative data quality within an experiment. Many different model specifications are possible, with the simplest fitting chip, and probe effects to the log\(_2\) intensities within each probeset across an experiment in a robust way. The output is a matrix of residuals, or weights for each chip which can be used as an additional diagnostic; systematically high residuals across an entire array, or a large fraction of an array is indicative of an outlier array. The main use of this tool is in deciding whether or not to keep an array in the down-stream data analysis.
Relative Log Expression (RLE)
The Relative Log Expression (RLE) values are computed by calculating for each probe-set the ratio between the expression of a probe-set and the median expression of this probe-set across all arrays of the experiment. It is assumed that most probe-sets are not changed across the arrays, so it is expected that these ratios are around 0 on a log scale. The boxplots presenting the distribution of these log-ratios should then be centered near 0 and have similar spread. Other behavior would be a sign of low quality.
Normalized Unscaled Standard Error (NUSE)
The Normalized Unscaled Standard Error (NUSE) is the individual probe error fitting the Probe-Level Model (the PLM models expression measures using a M-estimator robust regression). The NUSE values are standardized at the probe-set level across the arrays: median values for each probe-set are set to 1. The boxplots allow checking (1) if all distributions are centered near 1 (typically an array with a boxplot centered around 1.1 shows bad quality) and (2) if one array has globally higher spread of NUSE distribution than others, which may also be a sign of low quality.
library(affyPLM)
Loading required package: gcrma
Loading required package: preprocessCore
plmset <- fitPLM(raw)
NUSE(plmset,las=2)

RLE(plmset,las=2)

We can look at the images of the array surface. Ocassionally this can reveal problems on the array. See this gallery of interesting examples. Affymetrix, and other older arrays are vunerable to spatial artefacts as the same probe set is found in the same location on each chip.
If you want to look at an example of a bad array image, we can use the following code;
bad <- ReadAffy(celfile.path = "estrogen/",filenames="bad.cel")
image(bad)

Try out some images for this dataset
par(mfrow=c(2,4))
image(raw[,1])
image(raw[,2])
image(raw[,3])
image(raw[,4])
image(raw[,5])
image(raw[,6])
image(raw[,7])
image(raw[,8])

If we are happy with the quality of the raw data we can proceed to the next step. So far in the data, we have multiple probes within a probeset, and a perfect and mismatch measurement for each probe. These are not particular covenient values for statistical analysis as we would like a single measurement for each gene for each sample (/hybridisation).
Summarising and Normalising the Estrogen dataset
Many normalisation and summarisation methods have been developed for Affymetrix data. These include MAS5.0 and PLIER which were developed by Affymetrix, and RMA, GC-RMA, dChip and vsn (to name but a few) which have been developed by academic researchers. Many of these methods are available in the affy package. For a comparison of some of these methods and assessment of their performance on different control data sets, see Bolstad et al or Millenaar et al. In this practical we will use the RMA (Robust Multichip Averaging) method described in Irizarry et al.
Procedure;
- model based background adjustment
- followed by quantile normalisation and a
- robust summary method (median polish) on the log\(_2\) PM intensities
- to obtain probeset summary values.
Normalisation
- We want to be observing biological and not technical variation
- We wouldn’t expect such wholesale changes on a per-sample basis
Easy option would to scale values for each array to median level
What would happen if we had hybridised all the estrogen-treated samples on the first four arrays, and un-treated on the last four - Could you analyse the data? 
- Genes on array 2 are on average 2.6 lower than the global median, so add 2.6 to each gene
- Genes on array 8 are on average 0.7 higher than the global median, so subtract 0.7 from each gene
etc
Non-linear effects
As we saw before The MA-plot is commonly-used in microarray analysis to commonly-used to visualise differences between pairs of arrays. These plots can reveal non-linear effects and motivate more-sophisticated methods. On older array technologies, it was typical to see a banana-shaped trend on these plots.
(not our dataset)
Quantile normalisation
This is arguably the most-popular normalisation method available. Consider the following matrix of values to be normalised
Array1 Array2 Array3
[1,] "Rank4" "Rank5" "Rank3"
[2,] "Rank2" "Rank4" "Rank2"
[3,] "Rank3" "Rank3" "Rank1"
[4,] "Rank5" "Rank1" "Rank4"
[5,] "Rank1" "Rank2" "Rank5"
Sort each column Smallest…Largest
Sorted data
apply(raw.values, 2,sort)
Array1 Array2 Array3
[1,] 0.18 1.60 2.88
[2,] 0.72 1.65 3.12
[3,] 1.38 2.43 4.37
[4,] 2.19 2.92 4.93
[5,] 2.32 3.04 5.89
Then calculate target distribution by averaging the sorted rows
Rank1 Rank2 Rank3 Rank4 Rank5
1.553 1.830 2.727 3.347 3.750
Go back to the rank matrix
Array1 Array2 Array3
[1,] "Rank4" "Rank5" "Rank3"
[2,] "Rank2" "Rank4" "Rank2"
[3,] "Rank3" "Rank3" "Rank1"
[4,] "Rank5" "Rank1" "Rank4"
[5,] "Rank1" "Rank2" "Rank5"
Substitute with values from the target distribution
Rank1 Rank2 Rank3 Rank4 Rank5
1.553 1.830 2.727 3.347 3.750
ranked.values[,1] <- gsub("Rank1",target["Rank1"],ranked.values[,1])
ranked.values
Array1 Array2 Array3
[1,] "Rank4" "Rank5" "Rank3"
[2,] "Rank2" "Rank4" "Rank2"
[3,] "Rank3" "Rank3" "Rank1"
[4,] "Rank5" "Rank1" "Rank4"
[5,] "1.553" "Rank2" "Rank5"
ranked.values[,1] <- gsub("Rank2",target["Rank2"],ranked.values[,1])
ranked.values
Array1 Array2 Array3
[1,] "Rank4" "Rank5" "Rank3"
[2,] "1.83" "Rank4" "Rank2"
[3,] "Rank3" "Rank3" "Rank1"
[4,] "Rank5" "Rank1" "Rank4"
[5,] "1.553" "Rank2" "Rank5"
ranked.values[,1] <- gsub("Rank3",target["Rank3"],ranked.values[,1])
ranked.values
Array1 Array2 Array3
[1,] "Rank4" "Rank5" "Rank3"
[2,] "1.83" "Rank4" "Rank2"
[3,] "2.727" "Rank3" "Rank1"
[4,] "Rank5" "Rank1" "Rank4"
[5,] "1.553" "Rank2" "Rank5"
ranked.values[,1] <- gsub("Rank4",target["Rank4"],ranked.values[,1])
ranked.values
Array1 Array2 Array3
[1,] "3.347" "Rank5" "Rank3"
[2,] "1.83" "Rank4" "Rank2"
[3,] "2.727" "Rank3" "Rank1"
[4,] "Rank5" "Rank1" "Rank4"
[5,] "1.553" "Rank2" "Rank5"
ranked.values[,1] <- gsub("Rank5",target["Rank5"],ranked.values[,1])
ranked.values
Array1 Array2 Array3
[1,] "3.347" "Rank5" "Rank3"
[2,] "1.83" "Rank4" "Rank2"
[3,] "2.727" "Rank3" "Rank1"
[4,] "3.75" "Rank1" "Rank4"
[5,] "1.553" "Rank2" "Rank5"
for(i in 1:3){
ranked.values[,i] <- gsub("Rank1",target["Rank1"],ranked.values[,i])
ranked.values[,i] <- gsub("Rank2",target["Rank2"],ranked.values[,i])
ranked.values[,i] <- gsub("Rank3",target["Rank3"],ranked.values[,i])
ranked.values[,i] <- gsub("Rank4",target["Rank4"],ranked.values[,i])
ranked.values[,i] <- gsub("Rank5",target["Rank5"],ranked.values[,i])
}
ranked.values <- as.data.frame(ranked.values)
rownames(ranked.values) <- rownames(raw.values)
raw.values
ranked.values
Final Code
The procedure can be encapsulated in relatively few lines of code
ranked.values <- apply(raw.values, 2, function(x) paste("Rank",
rank(x,ties.method="min"),sep=""))
target <- round(rowMeans(apply(df, 2,sort)),3)
names(target) <- paste("Rank", 1:length(target),sep="")
for(i in 1:ncol(raw.values)){
for(nm in names(target)){
ranked.values[,i] <- gsub(nm,target[nm],ranked.values[,i])
}
}
norm <- as.data.frame(ranked.values)
We can use the normalizeQuantiles function within the limma package to do the normalisation.
library(limma)
?normalizeQuantiles
Caveats
- Distributions of samples are expected to be the same
- Majority of genes do not change between groups
- might be violated if you have samples that are dramatically altered
- e.g. low number of genes in a screening panel that are expected to change
Other normalisation procedures
- loess or splines
- need a reference or “average” array to compare
- estimate the curve and use to correct each point
library(affy)
?normalize.loess
Running RMA on our dataset
The affy package provides lots of different ways to process raw Affymetricx data, one of which is an implementation of RMA. For other methods, see the expresso function or package Vignette
?expresso
vignette("affy")
The result is an ExpressionSet, which is a ubiquitous object in Biooconductor for storing high-throughput data. Later-on in the course will we import data from public repositories, and these data will often be in a normalised form.
eset <- rma(raw)
Background correcting
Normalizing
Calculating Expression
eset
ExpressionSet (storageMode: lockedEnvironment)
assayData: 12625 features, 8 samples
element names: exprs
protocolData
sampleNames: low10-1.cel low10-2.cel ... high48-2.cel (8 total)
varLabels: ScanDate
varMetadata: labelDescription
phenoData
sampleNames: low10-1.cel low10-2.cel ... high48-2.cel (8 total)
varLabels: estrogen time.h
varMetadata: labelDescription
featureData: none
experimentData: use 'experimentData(object)'
Annotation: hgu95av2
The ExpressionSet is a convenient object-type for storing multiple high-dimensional data frames. The structure of the object is much more complicated than other types of data we have seen before. In fact we do not need to know need exactly how the object is constructed internally. The package authors have provided convenient functions that will allow us to access the data.
For example, if we want to extract the expression measurements themselves the function to use is called exprs. The result will be a matrix with one row for each gene, and one column for each sample.
head(exprs(eset))
low10-1.cel low10-2.cel high10-1.cel high10-2.cel low48-1.cel low48-2.cel high48-1.cel
100_g_at 9.642896 9.741496 9.537036 9.353625 9.591697 9.570590 9.475796
1000_at 10.398169 10.254362 10.003971 9.903528 10.374866 10.033520 10.345066
1001_at 5.717613 5.881008 5.859563 5.954028 5.960540 6.020889 5.981080
1002_f_at 5.512596 5.801807 5.571065 5.608132 5.390064 5.494511 5.508104
1003_s_at 7.783927 8.007975 8.037999 7.835120 7.926487 8.138870 7.994937
1004_at 7.289162 7.603670 7.488539 7.771506 7.521789 7.599544 7.456149
high48-2.cel
100_g_at 9.530655
1000_at 9.863321
1001_at 6.285192
1002_f_at 5.630107
1003_s_at 8.233338
1004_at 7.675171
summary(exprs(eset))
low10-1.cel low10-2.cel high10-1.cel high10-2.cel low48-1.cel
Min. : 4.269 Min. : 4.280 Min. : 4.294 Min. : 4.135 Min. : 4.238
1st Qu.: 5.601 1st Qu.: 5.628 1st Qu.: 5.592 1st Qu.: 5.621 1st Qu.: 5.630
Median : 7.108 Median : 7.123 Median : 7.108 Median : 7.123 Median : 7.102
Mean : 7.295 Mean : 7.295 Mean : 7.293 Mean : 7.293 Mean : 7.291
3rd Qu.: 8.600 3rd Qu.: 8.592 3rd Qu.: 8.616 3rd Qu.: 8.607 3rd Qu.: 8.588
Max. :14.736 Max. :14.763 Max. :14.765 Max. :14.733 Max. :14.750
low48-2.cel high48-1.cel high48-2.cel
Min. : 4.306 Min. : 4.273 Min. : 4.327
1st Qu.: 5.636 1st Qu.: 5.591 1st Qu.: 5.626
Median : 7.094 Median : 7.063 Median : 7.078
Mean : 7.267 Mean : 7.287 Mean : 7.257
3rd Qu.: 8.570 3rd Qu.: 8.598 3rd Qu.: 8.571
Max. :14.761 Max. :14.706 Max. :14.716
You will notice the rma also incorporates a log\(_2\) transformation. The values present in the cel files are derived from processing the TIFF images of the chip surface, which are on the scale 0 - 2^16. However, this is not a very convenient scale for visualisation and analysis as most of the observations are found at the lower end of the scale and there is a much greater variance at the higer values. We say that the data exhibit ‘heteroscedasticity’. To alleviate this we can use a data transformation such as log\(_2\) and afterwards our data will be in the range 0 to 16. Another method you may come across is vsn.
boxplot(exprs(eset),las=2)

How can you tell from the boxplot that these data have been normalised?
An MA-plot can be repeated on the normalised data to verify that the normalisation procedure has been sucessful.
mva.pairs(exprs(eset)[,1:4],log.it = FALSE,plot.method="smoothScatter")

If we have used a targets file to read the raw data, this information will stored in the summarised object. Commonly-referred to as “pheno data”, this can retrieved using the pData function. A nice property of this data frame is that the rows are arranged in the same order as the columns of the expression matrix. i.e. The first column of the expression matrix is described in the first row of the pheno data matrix, and so on.
head(pData(eset))
colnames(exprs(eset))
[1] "low10-1.cel" "low10-2.cel" "high10-1.cel" "high10-2.cel" "low48-1.cel" "low48-2.cel"
[7] "high48-1.cel" "high48-2.cel"
rownames(pData(eset))
[1] "low10-1.cel" "low10-2.cel" "high10-1.cel" "high10-2.cel" "low48-1.cel" "low48-2.cel"
[7] "high48-1.cel" "high48-2.cel"
Clustering techniques and PCA that we will meet later in the course can also inform decisions about experiment quality by providing a way of visualing relationships between sample groups.
Automated production of QC plots
The arrayQualityMetrics package is able to produce QA plots from set of cel files, or a normalised dataset.
library(arrayQualityMetrics)
arrayQualityMetrics(eset)
Thoughts on Quality Assessment
- It is difficult to come up with definitive rules about when to reject a sample from the analysis
- Try and keep as much information from the lab
- RIN (RNA Integrity Numbers), tumour composition
- If we try and reject samples for looking different, we might bias our results and miss interesting findings
- If the majority of our samples are poor quality, the better quality ones might stand-out as outliers!
- Try and collect as many samples / replicates as possible to be tolerant to variation
Summary
- Affy data come in
.cel files that can be imported with the affy package
- QC checks on the raw data include;
- check the chip image
- probe-level models
- boxplots
- Affy data need to be summarised before further analysis
rma (and variants thereof) is most-popular
- Affy data can be summarised into a common Bioconductor object-type
- The
ExpressionSet, or derivaties thereof, is used throughout Bioconductor to represent all types of high-throughput data
- methylation, ChIP, RNA-seq
- basically anything where you can have some kind of genomic measure as rows, and samples as columns
LS0tCnRpdGxlOiAiVGhlIEFmZnltZXRyaXggQW5hbHlzaXMgV29ya2Zsb3ciCmF1dGhvcjogTWFyayBEdW5uaW5nLCBiYXNlZCBvbiBtYXRlcmlhbHMgYnkgQmVuaWx0b24gQ2FydmFsaG8Kb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwotLS0KCgohW10oaHR0cHM6Ly91cGxvYWQud2lraW1lZGlhLm9yZy93aWtpcGVkaWEvY29tbW9ucy8yLzIyL0FmZnltZXRyaXgtbWljcm9hcnJheS5qcGcpCgojIFRlY2hub2xvZ3kgb3ZlcnZpZXcKCkFmZnltZXRyaXggbWljcm9hcnJheXMgYXJlIGEgcG9wdWxhciBjb21tZXJjaWFsIHBsYXRmb3JtIGF2YWlsYWJsZSBmb3IgYSB3aWRlIHJhbmdlIG9mCmdlbm9taWNzIGFwcGxpY2F0aW9ucyAoZ2VuZSBleHByZXNzaW9uIHByb2ZpbGluZywgU05QIGdlbm90eXBpbmcsIENoSVAtY2hpcCBhbmFseXNpcyBldGMuKQppbiBkaWZmZXJlbnQgc3BlY2llcy4KVGhlIG1haW4gZGlzdGluY3Rpb24gYmV0d2VlbiBBZmZ5bWV0cml4IGFuZCBvdGhlciBhcnJheSB0ZWNobm9sb2dpZXMgaXMgdGhlIHVzZSBvZiBtYW55CnNob3J0ICgyNW1lcikgcHJvYmVzIHRvIG1lYXN1cmUgaHlicmlkaXNhdGlvbi4KSW4gdGhpcyBwcmFjdGljYWwsIHdlIGV4cGxvcmUgdGhlIGJhc2ljIGFuYWx5c2lzIGlzc3VlcyBmb3IgQWZmeW1ldHJpeCBHZW5lQ2hpcHMgd2hpY2ggbWVhc3VyZSBnZW5lIGV4cHJlc3Npb24gdXNpbmcgbXVsdGlwbGUgKDExLTIwKSBwZXJmZWN0IG1hdGNoIChQTSkgYW5kIG1pc21hdGNoIChNTSkgcHJvYmVzCmNvbmNlbnRyYXRlZCBpbiB0aGUgM+KAmSByZWdpb24gb2YgZWFjaCB0cmFuc2NyaXB0LiAKCiFbXShpbWFnZXMvcG0ucG5nKQoKRGVzcGl0ZSBvdXIgZm9jdXMgb24gZXhwcmVzc2lvbiBhcnJheXMsIG1hbnkKb2YgdGhlIHByb2Nlc3Npbmcgc3RlcHMsIHN1Y2ggYXMgcXVhbGl0eSBhc3Nlc3NtZW50IGFuZCBub3JtYWxpc2F0aW9uIGFyZSBlcXVhbGx5IGltcG9ydGFudApmb3Igb3RoZXIgYXBwbGljYXRpb25zIG9mIEFmZnltZXRyaXggdGVjaG5vbG9neSB0byBlbnN1cmUgdGhhdCB0aGUgc2lnbmFsIGlzIGNvbXBhcmFibGUgYmV0d2VlbiBhcnJheXMuCkluIHRoaXMgcHJhY3RpY2FsIHdlIHVzZSBzZXZlcmFsIEJpb2NvbmR1Y3RvciBwYWNrYWdlcyAoW2FmZnldKGh0dHA6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy9odG1sL2FmZnkuaHRtbCksIFthZmZ5UExNXShodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvaHRtbC9hZmZ5UExNLmh0bWwpLCBbbGltbWFdKGh0dHA6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy9odG1sL2xpbW1hLmh0bWwpLCBldGMuKSB0byByZWFkIGluCnRoZSByYXcgZGF0YSwgYXNzZXNzIGRhdGEgcXVhbGl0eSBhbmQgbm9ybWFsaXNlIGFuIEFmZnltZXRyaXggZXhwZXJpbWVudC4gUmF3IGRhdGEgZm9yIEFmZnltZXRyaXggYXJyYXlzIGFyZSB1c3VhbGx5IHN0b3JlZCBpbiBbYC5jZWxgXShodHRwOi8vZGVwdC5zdGF0LmxzYS51bWljaC5lZHUvfmtzaGVkZGVuL0NvdXJzZXMvU3RhdDU0NS9Ob3Rlcy9BZmZ4RmlsZUZvcm1hdHMvY2VsLmh0bWwpIGZvcm1hdC4gV2Ugd291bGRuJ3Qgbm9ybWFsbHkgd2lzaCB0byB2aWV3IHRoZXNlIGZpbGVzIGRpcmVjdGx5LiBUaGVzZSBmaWxlcyBjb250YWluIHRoZSBpbnRlbnNpdGllcyBvZiBlYWNoICJjZWxsIiBvbiBjaGlwIHN1cmZhY2UgYWZ0ZXIgaW1hZ2UgYW5hbHlzaXMuIAoKICAtIEVhY2ggaHlicmlkaXNhdGlvbiBoYXMgYSB1bmlxdWUgKmNlbCogZmlsZQogIC0gSXQgaXMga25vdyBpbiBhZHZhbmNlIHdoaWNoIHByb2JlIC8gcHJvYmUgc2V0IGlzIGxvY2F0ZWQgd2l0aGluIGVhY2ggY2VsbAogIC0gRWFjaCBjaGlwIHR5cGUgKGUuZy5oZ3U5NWF2MikgaGFzIGEgKmNkZiogKGNoaXAgZGVzY3JpcHRpb24pIGZpbGUgd2hpY2ggaXMgcmVxdWlyZWQgdG8gZGVjb2RlIHdoaWNoIHByb2JlIGFuZCBwcm9iZSBzZXQgaXMgd2l0aGluIGVhY2ggY2VsbC4KCiMgRXhhbXBsZSBhbmFseXNpcyBpbiBSCgojIyBUaGUgZXN0cm9nZW4gZGF0YXNldAoKVGhlIGV4cGVyaW1lbnQgd2Ugd2lsbCBhbmFseXNlIGlzIG1hZGUtdXAgb2YgZWlnaHQgQWZmeW1ldHJpeCAqSEdVOTVBdjIqCkdlbmVDaGlwcy4gVGhlIGFpbSBvZiB0aGUgZXhwZXJpbWVudCBpcyBicmllZmx5IGRlc2NyaWJlZCBiZWxvdyAoZXhjZXJwdCB0YWtlbiBmcm9tIHRoZQpmYWN0RGVzaWduIHBhY2thZ2UgdmlnbmV0dGUpLgoKPiDigJxUaGUgaW52ZXN0aWdhdG9ycyBpbiB0aGlzIGV4cGVyaW1lbnQgd2VyZSBpbnRlcmVzdGVkIGluIHRoZSBlZmZlY3Qgb2YgZXN0cm9nZW4gb24gdGhlIGdlbmVzIGluIEVSKyBicmVhc3QgY2FuY2VyIGNlbGxzIG92ZXIgdGltZS4gQWZ0ZXIgc2VydW0gc3RhcnZhdGlvbiBvZiBhbGwgZWlnaHQgc2FtcGxlcywgdGhleSBleHBvc2VkCmZvdXIgc2FtcGxlcyB0byBlc3Ryb2dlbiwgYW5kIHRoZW4gbWVhc3VyZWQgbVJOQSB0cmFuc2NyaXB0IGFidW5kYW5jZSBhZnRlciAxMCBob3VycyBmb3IKdHdvIHNhbXBsZXMgYW5kIDQ4IGhvdXJzIGZvciB0aGUgb3RoZXIgdHdvLiBUaGV5IGxlZnQgdGhlIHJlbWFpbmluZyBmb3VyIHNhbXBsZXMgdW50cmVhdGVkLAphbmQgbWVhc3VyZWQgbVJOQSB0cmFuc2NyaXB0IGFidW5kYW5jZSBhdCAxMCBob3VycyBmb3IgdHdvIHNhbXBsZXMsIGFuZCA0OCBob3VycyBmb3IKdGhlIG90aGVyIHR3by4gU2luY2UgdGhlcmUgYXJlIHR3byBmYWN0b3JzIGluIHRoaXMgZXhwZXJpbWVudCAoZXN0cm9nZW4gYW5kIHRpbWUpLCBlYWNoIGF0CnR3byBsZXZlbHMgKHByZXNlbnQgb3IgYWJzZW50LCAxMCBob3VycyBvciA0OCBob3VycyksIHRoaXMgZXhwZXJpbWVudCBpcyBzYWlkIHRvIGhhdmUgYSAyIMOXIDIKZmFjdG9yaWFsIGRlc2lnbi7igJ0KClRoZSBkYXRhIGZvciB0aGlzIHNlY3Rpb24gYXJlIGRlc2NyaWJlZCBpbiB0aGUgW2VzdHJvZ2VuIGRhdGEgcGFja2FnZV0oaHR0cDovL3d3dy5iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvZGF0YS9leHBlcmltZW50L2h0bWwvZXN0cm9nZW4uaHRtbCkgaW4gQmlvY29uZHVjdG9yCgpUaGUgY2VsIGZpbGVzIGZvciB0aGUgZXhhbXBsZSBleHBlcmllbWVudCBhcmUgc3RvcmVkIGluIHRoZSBgZXN0cm9nZW5gIGRpcmVjdG9yeQoKVGhlIGZpcnN0IHN0YWdlIGlzIHRvIHJlYWQgdGhlICp0YXJnZXRzKiBmaWxlLiBJbiBCaW9jb25kdWN0b3Igd2Ugb2Z0ZW4gdXNlIGEgdGFyZ2V0cyBmaWxlIHRvIGRlZmluZSB0aGUgZmlsZXMgY29ycmVzcG9uZGluZyB0byB0aGUgcmF3IGRhdGEgZm9yIHRoZSBleHBlcmltZW50IGFuZCB3aGljaCBzYW1wbGUgZ3JvdXBzIHRoZXkgYmVsb25nIHRvLiBTdWNoIGEgZmlsZSBjYW4gYmUgY3JlYXRlZCBpbiBhIHNwcmVhZHNoZWV0LCBvciB0ZXh0IGVkaXRvciwgYW5kIHVzdWFsbHkgc2F2ZWQgYXMgYSB0YWItZGVsaW1pdGVkIGZpbGUuIFdlIGNhbiBoYXZlIGFzIG1hbnkgY29sdW1ucyBpbiB0aGUgZmlsZSBhcyB3ZSBzZWUgZml0LCBhbmQgb25lIHJvdyBmb3IgZWFjaCBoeWJyaWRpc2F0aW9uLiBUaGUgc2FtcGxlIGdyb3VwIGluZm9ybWF0aW9uIGlzIHByb3BvZ2F0ZWQgdGhyb3VnaCB0aGUgYW5hbHlzaXMgYW5kIGluY29ycG9yYXRlZCBpbiB0aGUgcXVhbGl0eSBhc3Nlc3NtZW50IGFuZCBldmVudHVhbGx5IGRpZmZlcmVudGlhbCBleHByZXNzaW9uLiBXZSByZWZlciB0byB0aGlzIGFzIHRoZSAicGhlbm90eXBlIGRhdGEiIGZvciB0aGUgZXhwZXJpbWVudCwgb3Igc29tZXRpbWVzIHRoZSAqIm1ldGFkYXRhIiouCgojIyMgUGFja2FnZXMgYW5kIGRhdGEgCgpJZiB5b3UgZGlkIG5vdCBpbnN0YWxsIHRoZSBgYWZmeWAgQmlvY29uZHVjdG9yIHBhY2thZ2UsIHlvdSB3aWxsIG5lZWQgdG8gZG8gc28gbm93Oi0KCmBgYHtyIGV2YWw9RkFMU0V9CnNvdXJjZSgiaHR0cDovL3d3dy5iaW9jb25kdWN0b3Iub3JnL2Jpb2NMaXRlLlIiKQpiaW9jTGl0ZSgiYWZmeSIpCmBgYAoKVGhlIGRhdGEgZm9yIHRoZSBwcmFjdGljYWwgY2FuIGJlIGZvdW5kIGluIHRoZSBbY291cnNlIHppcCBmaWxlXShodHRwczovL3Jhd2dpdC5jb20vYmlvaW5mb3JtYXRpY3MtY29yZS1zaGFyZWQtdHJhaW5pbmcvbWljcm9hcnJheS1hbmFseXNpcy9tYXN0ZXIvQ291cnNlX0RhdGEuemlwKQoKYGBge3J9CmxpYnJhcnkoYWZmeSkKdGFyZ2V0c0ZpbGUgPC0gImVzdHJvZ2VuL2VzdHJvZ2VuLnR4dCIKdGFyZ2V0c0ZpbGUKcGQgPC0gcmVhZC5Bbm5vdGF0ZWREYXRhRnJhbWUodGFyZ2V0c0ZpbGUsaGVhZGVyPVRSVUUsc2VwPSIiLHJvdy5uYW1lcz0xKQpwRGF0YShwZCkKYGBgCgoKCkFzIGAuY2VsYCBmaWxlcyBhcmUgbm90IGEgdHlwaWNhbCBmaWxlIGZvcm1hdCwgd2UgY2Fubm90IHVzZSB0aGUgc3RhbmRhcmQgUiBmdW5jdGlvbnMgc3VjaCBhcyBgcmVhZC5kZWxpbWAsIGByZWFkLmNzdmAgYW5kIGByZWFkLnRhYmxlYC4gVGhlIGZ1bmN0aW9uIHRvIGltcG9ydCB0aGUgZGF0YSBpcyBgUmVhZEFmZnlgIGZyb20gdGhlIFthZmZ5XShodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvaHRtbC9hZmZ5Lmh0bWwpIHBhY2thZ2UuIAoKYGBge3J9CgpyYXcgPC1SZWFkQWZmeShjZWxmaWxlLnBhdGggPSAiZXN0cm9nZW4iLCBmaWxlbmFtZXM9cm93bmFtZXMocERhdGEocGQpKSxwaGVub0RhdGEgPSBwZCkKcmF3CmBgYAoKKioqKioqCldoYXQgdHlwZSBvZiBBZmZ5IGFycmF5IGlzIHRoaXMKSG93IG1hbnkgZmVhdHVyZXM/CkhvdyBtYW55IHNhbXBsZXM/CgoqKioqKioKCgoKCiMjIERpYWdub3N0aWMgcGxvdHMgCgpBcyB3aXRoIG90aGVyIGhpZ2gtdGhyb3VnaHB1dCB0ZWNobm9sb2dpZXMsIHF1YWxpdHkgYXNzZXNzbWVudCBpcyBhbiBpbXBvcnRhbnQgcGFydCBvZiB0aGUKYW5hbHlzaXMgcHJvY2Vzcy4gRGF0YSBxdWFsaXR5IGNhbiBiZSBjaGVja2VkIHVzaW5nIHZhcmlvdXMgZGlhZ25vc3RpYyBwbG90cy4KClRoZSBmaXJzdCBkaWFnbm9zdGljIHBsb3Qgd2Ugd2lsbCBtZWV0IGlzIHRoZSAiW2JveHBsb3RdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0JveF9wbG90KSIsIHdoaWNoIGlzIGEgY29tbW9ubHktdXNlZCBwbG90IGluIGRhdGEgYW5hbHlzaXMgZm9yICpjb21wYXJpbmcgZGF0YSBkaXN0cmlidXRpb25zKi4gVGhlIGV4YWN0IGRlZmluaXRpb24gb2YgaG93IGlzIGJveHBsb3QgaXMgZHJhd24gY2FuIHZhcnksIHRoZSBkZWZpbml0aW9ucyBhbHdheXMgaG9sZDsKCi0gVGhlIGJvdHRvbSBvZiB0aGUgYm94IGlzIHRoZSAqZmlyc3QgcXVhcnRpbGUqOyB0aGUgMjV0aCBwZXJjZW50aWxlCi0gVGhlIHRvcCBvZiB0aGUgYm94IGlzIHRoZSAqdGhpcmQgcXVhcnRpbGUqOyB0aGUgNzV0aCBwZXJjZW50aWxlCi0gVGhlIG1lZGlhbiBpcyByZXByZXNlbnRlZCBieSBhIGhvcml6b250YWwgbGluZQotIFRoZSAqaW50ZXItcXVhcnRpbGUgcmFuZ2UqIChJUVIpIGlzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIDc1dGggYW5kIDI1dGggcGVyY2VudGlsZXMKCkhlcmUsIHdlIGRyYXcgYSBib3hwbG90IHRvIGNvbXBhcmUgdHdvIGRpc3RyaWJ1dGlvbnM7IGB4YCB3aXRoIGEgbWVhbiBvZiAwIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gb2YgMSwgYW5kIGB5YCB3aXRoIGEgbWVhbiBvZiAyIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gb2YgNC4KCmBgYHtyfQp4IDwtIHJub3JtKDEwMCkKeSA8LSBybm9ybSgxMDAsIG1lYW4gPSAyLHNkPTQpCmJveHBsb3QoeCx5KQpgYGAKCkl0IGlzIGFsc28gY29tbW9uIHRvIGRyYXcgd2hpc2tlcnMgdGhhdCBleHRlbmQgdG8gMS41IFggdGhlIElRUiBmcm9tIHRoZSBsb3dlciBhbmQgdXBwZXIgcXVhcnRpbGUuIEFueSBwb2ludHMgb3V0c2lkZSB0aGlzIHJhbmdlIGNhbiBiZSByZXByZXNlbnRlZCBieSBhIGRvdC4KCgpJbiBCaW9jb25kdWN0b3IsIHlvdSB3aWxsIHVzdWFsbHkgZmluZCB0aGF0IHBhY2thZ2UgYXV0aG9ycyBoYXZlIGNyZWF0ZWQgc2hvcnRjdXRzIHRvIGFsbG93IGNvbXBsaWNhdGVkIGRhdGEgdHlwZXMgdG8gYmUgdmlzdWFsaXNlZCB3aXRoIGNvbW1vbiBmdW5jdGlvbnMuIEZvciBpbnN0YW5jZSwgaWYgd2Ugd2FudCB0byBjb25zdHJ1Y3QgYSBib3hwbG90IGZyb20gb3VyIHJhdyBBZmZ5bWV0cml4IGRhdGEgaXQgd291bGQgYmUgcXVpdGUgYSBkYXVudGluZyB0YXNrIGZvciB0aGUgbm92aWNlIHRvIGV4dHJhY3QgdGhlIHJldmVsYW50IGluZm9ybWF0aW9uIGZyb20gdGhlIG9iamVjdC4gSW5zdGVhZCwgd2UgY2FuIHVzZSBmdW5jdGlvbnMgdGhhdCB3ZSBhcmUgZmFtaWxpYXIgd2l0aCBzdWNoIGFzIGBib3hwbG90YC4gVGhlIHBsb3QgY2FuIGFsc28gYmUgY3VzdG9taXNlZCBpbiB3YXlzIHRoYXQgd2UgYXJlIGZhbWlsaWFyIHdpdGggc3VjaCBhcyBjaGFuZ2luZyB0aGUgY29sb3IgKHRoZSBgY29sYCBhcmd1bWVudCkgYW5kIGxhYmVsIG9yaWVudGF0aW9uIChgbGFzPTJgIHRvIG1ha2UgbGFiZWxzIHBlcnBlbmRpY3VsYXIgdG8gdGhlIGF4aXMpCgpgYGB7cn0KYm94cGxvdChyYXcsY29sPSJyZWQiLGxhcz0yKQpgYGAKCioqKioqKgoKIyMjIFdoYXQgZG8geW91IG5vdGljZSBmcm9tIHRoaXMgcGxvdD8KCioqKioqKgoKCiMjIFBlcmZlY3QtTWF0Y2ggYW5kIE1pc21hdGNoIHByb2JlcwoKV2l0aCB0aGUgc2hvcnQgRE5BIHNlcXVlbmNlcyB1c2VkIGZvciBtaWNyb2FycmF5IGh5YnJpZGlzYXRpb24sIHRoZXJlIGlzIHRoZSBwb3NzaWJpbGl0eSBmb3IgdGhlIHNlcXVlbmNlIGRlc2lnbmVkIHRvIG5vdCBiZSBzcGVjaWZpYy1lbm91Z2ggYW5kIGh5YnJpZGlzZSB0byBtYW55IHJlZ2lvbnMgb2YgdGhlIGdlbm9tZS4gQWZmeW1ldHJpeCBhdHRlbXB0IHRvIHJlc29sdmUgdGhpcyBpc3N1ZSBieSBoYXZpbmcgYSBtaXNtYXRjaCBzZXF1ZW5jZSBjb3JyZXNwb25kaW5nIHRvIGVhY2ggcHJvYmUuIElkZWFsbHksIHRoZSBzdWJ0cmFjdGluZyB0aGUgbWlzbWF0Y2ggZnJvbSB0aGUgY29ycmVzcG9uZGluZyBwZXJmZWN0IG1hdGNoKCAkUE0gLSBNTSQpIHNob3VsZCB5aWVsZCBhIGJhY2tncm91bmQtY29ycmVjdGVkLCBhbmQgbW9yZS1yZWxpYWJsZSwgc2lnbmFsLgoKCioqKioqKgoKR2VuZXJhdGUgaGlzdG9ncmFtcyBvZiB0aGUgUE0gYW5kIE1NIGludGVuc2l0aWVzIGZyb20gdGhlIGZpcnN0IGFycmF5LiBEbyB5b3UKbm90aWNlIGFueSBkaWZmZXJlbmNlIGluIHRoZSBzaWduYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSBQTXMgYW5kIE1Ncz8KCioqKioqKgoKYGBge3J9CnBhcihtZnJvdz1jKDIsMSkpCmhpc3QobG9nMihwbShyYXdbLDFdKSksYnJlYWtzPTEwMCxjb2w9InN0ZWVsYmx1ZSIsbWFpbj0iUE0iLHhsaW09Yyg0LDE0KSkKaGlzdChsb2cyKG1tKHJhd1ssMV0pKSxicmVha3M9MTAwLGNvbD0ic3RlZWxibHVlIixtYWluPSJNTSIseGxpbT1jKDQsMTQpKQoKYGBgCgoKCioqKk0tQSoqKiBwbG90cyBhcmUgYSB1c2VmdWwgd2F5IG9mIGNvbXBhcmluZyB0aGUgcmVkIGFuZCBncmVlbiBjaGFubmVscyBmcm9tIGEgdHdvLWNvbG91cgptaWNyb2FycmF5LiBGb3IgQWZmeW1ldHJpeCBkYXRhLCB3aGljaCBpcyBhIHNpbmdsZS1jaGFubmVsIHRlY2hub2xvZ3ksIE0gYW5kIEEgdmFsdWVzIGNhbgpiZSBjYWxjdWxhdGVkIHVzaW5nIHRoZSBpbnRlbnNpdGllcyBmcm9tIGEgcGFpciBvZiBjaGlwcy4gV2Ugd291bGQgdHlwaWNhbGx5IHByb2R1Y2UgYSBwbG90IHVzaW5nIHNhbXBsZXMgZnJvbSB0aGUgc2FtZSBiaW9sb2dpY2FsIGdyb3VwLCB3aGVyZSB3ZSB3b3VsZCBub3QgZXhwZWN0IHRvIG9ic2VydmUgbXVjaCBkaWZmZXJlbmNlIGluIGludGVuc2l0eSBmb3IgYSBnaXZlbiBnZW5lLgoKaS5lLiBpZiBYJF9pJCBpcyB0aGUgaW50ZW5zaXR5IG9mIGEgZ2l2ZW4KcHJvYmUgZnJvbSBjaGlwICRpJCBhbmQgWCRfaiQgaXMgdGhlIGludGVuc2l0eSBmb3IgdGhlIHNhbWUgcHJvYmUgb24gY2hpcCAkaiQsIHRoZW4gCiRBID0gMS8yIChsb2dfMihYX2kpICsgbG9nXzIoWF9qKSkkIGFuZCAkTSA9IGxvZ18yKFhfaSkg4oiSIGxvZ18yKFhfaikkIC4gSW4gdGhpcyBleHBlcmltZW50LCB0aGVyZSBhcmUgOCBHZW5lQ2hpcHMsIHdoaWNoIGdpdmVzCjI4IGRpc3RpbmN0IHBhaXItd2lzZSBjb21wYXJpc29ucyBiZXR3ZWVuIGFycmF5cy4gV2Ugd2lsbCBmb2N1cyBvbiBhIHN1YnNldCBvZiB0aGVzZSBiZWxvdy4KCmBgYHtyfQptdmEucGFpcnMocG0ocmF3KVssMTo0XSxwbG90Lm1ldGhvZD0ic21vb3RoU2NhdHRlciIpCm12YS5wYWlycyhwbShyYXcpWyw1OjhdLHBsb3QubWV0aG9kPSJzbW9vdGhTY2F0dGVyIikKYGBgCgoKKioqKioqCkJhc2VkIG9uIGFsbCB0aGUgcGxvdHMgeW91IGhhdmUgZ2VuZXJhdGVkLCB3aGF0IHdvdWxkIHlvdSBjb25jbHVkZSBhYm91dCB0aGUgb3ZlcmFsbCBxdWFsaXR5IG9mIHRoaXMgZXhwZXJpbWVudD8gCioqKioqKgoKCgojIyBQcm9iZS1sZXZlbCBMaW5lYXIgTW9kZWxzCgpQcm9iZS1sZXZlbCBMaW5lYXIgTW9kZWxzIChQTE1zKSBjYW4gYmUgdXNlZCBhcyBhbiBhZGRpdGlvbmFsIHRvb2wgdG8gYXNzZXNzIHJlbGF0aXZlCmRhdGEgcXVhbGl0eSB3aXRoaW4gYW4gZXhwZXJpbWVudC4gTWFueSBkaWZmZXJlbnQgbW9kZWwgc3BlY2lmaWNhdGlvbnMgYXJlIHBvc3NpYmxlLCB3aXRoCnRoZSBzaW1wbGVzdCBmaXR0aW5nIGNoaXAsIGFuZCBwcm9iZSBlZmZlY3RzIHRvIHRoZSBsb2ckXzIkIGludGVuc2l0aWVzIHdpdGhpbiBlYWNoIHByb2Jlc2V0IGFjcm9zcwphbiBleHBlcmltZW50IGluIGEgcm9idXN0IHdheS4KVGhlIG91dHB1dCBpcyBhIG1hdHJpeCBvZiByZXNpZHVhbHMsIG9yIHdlaWdodHMgZm9yIGVhY2ggY2hpcCB3aGljaCBjYW4gYmUgdXNlZCBhcyBhbiBhZGRpdGlvbmFsIGRpYWdub3N0aWM7IHN5c3RlbWF0aWNhbGx5IGhpZ2ggcmVzaWR1YWxzIGFjcm9zcyBhbiBlbnRpcmUgYXJyYXksIG9yIGEgbGFyZ2UgZnJhY3Rpb24gb2YgYW4gYXJyYXkgaXMgaW5kaWNhdGl2ZSBvZiBhbiBvdXRsaWVyIGFycmF5LiBUaGUgbWFpbiB1c2Ugb2YgdGhpcyB0b29sIGlzIGluIGRlY2lkaW5nIHdoZXRoZXIgb3IKbm90IHRvIGtlZXAgYW4gYXJyYXkgaW4gdGhlIGRvd24tc3RyZWFtIGRhdGEgYW5hbHlzaXMuCgojIyMgUmVsYXRpdmUgTG9nIEV4cHJlc3Npb24gKFJMRSkKClRoZSBSZWxhdGl2ZSBMb2cgRXhwcmVzc2lvbiAoUkxFKSB2YWx1ZXMgYXJlIGNvbXB1dGVkIGJ5IGNhbGN1bGF0aW5nIGZvciBlYWNoIHByb2JlLXNldCB0aGUgcmF0aW8gYmV0d2VlbiB0aGUgZXhwcmVzc2lvbiBvZiBhIHByb2JlLXNldCBhbmQgdGhlIG1lZGlhbiBleHByZXNzaW9uIG9mIHRoaXMgcHJvYmUtc2V0IGFjcm9zcyBhbGwgYXJyYXlzIG9mIHRoZSBleHBlcmltZW50LiBJdCBpcyBhc3N1bWVkIHRoYXQgbW9zdCBwcm9iZS1zZXRzIGFyZSBub3QgY2hhbmdlZCBhY3Jvc3MgdGhlIGFycmF5cywgc28gaXQgaXMgZXhwZWN0ZWQgdGhhdCB0aGVzZSByYXRpb3MgYXJlIGFyb3VuZCAwIG9uIGEgbG9nIHNjYWxlLiBUaGUgYm94cGxvdHMgcHJlc2VudGluZyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZXNlIGxvZy1yYXRpb3Mgc2hvdWxkIHRoZW4gYmUgY2VudGVyZWQgbmVhciAwIGFuZCBoYXZlIHNpbWlsYXIgc3ByZWFkLiBPdGhlciBiZWhhdmlvciB3b3VsZCBiZSBhIHNpZ24gb2YgbG93IHF1YWxpdHkuCgoKIyMjIE5vcm1hbGl6ZWQgVW5zY2FsZWQgU3RhbmRhcmQgRXJyb3IgKE5VU0UpIAoKVGhlIE5vcm1hbGl6ZWQgVW5zY2FsZWQgU3RhbmRhcmQgRXJyb3IgKE5VU0UpIGlzIHRoZSBpbmRpdmlkdWFsIHByb2JlIGVycm9yIGZpdHRpbmcgdGhlIFByb2JlLUxldmVsIE1vZGVsICh0aGUgUExNIG1vZGVscyBleHByZXNzaW9uIG1lYXN1cmVzIHVzaW5nIGEgTS1lc3RpbWF0b3Igcm9idXN0IHJlZ3Jlc3Npb24pLiBUaGUgTlVTRSB2YWx1ZXMgYXJlIHN0YW5kYXJkaXplZCBhdCB0aGUgcHJvYmUtc2V0IGxldmVsIGFjcm9zcyB0aGUgYXJyYXlzOiBtZWRpYW4gdmFsdWVzIGZvciBlYWNoIHByb2JlLXNldCBhcmUgc2V0IHRvIDEuIFRoZSBib3hwbG90cyBhbGxvdyBjaGVja2luZyAoMSkgaWYgYWxsIGRpc3RyaWJ1dGlvbnMgYXJlIGNlbnRlcmVkIG5lYXIgMSAodHlwaWNhbGx5IGFuIGFycmF5IHdpdGggYSBib3hwbG90IGNlbnRlcmVkIGFyb3VuZCAxLjEgc2hvd3MgYmFkIHF1YWxpdHkpIGFuZCAoMikgaWYgb25lIGFycmF5IGhhcyBnbG9iYWxseSBoaWdoZXIgc3ByZWFkIG9mIE5VU0UgZGlzdHJpYnV0aW9uIHRoYW4gb3RoZXJzLCB3aGljaCBtYXkgYWxzbyBiZSBhIHNpZ24gb2YgbG93IHF1YWxpdHkuCgpgYGB7cn0KbGlicmFyeShhZmZ5UExNKQpwbG1zZXQgPC0gZml0UExNKHJhdykKTlVTRShwbG1zZXQsbGFzPTIpClJMRShwbG1zZXQsbGFzPTIpCmBgYAoKCldlIGNhbiBsb29rIGF0IHRoZSBpbWFnZXMgb2YgdGhlIGFycmF5IHN1cmZhY2UuIE9jYXNzaW9uYWxseSB0aGlzIGNhbiByZXZlYWwgcHJvYmxlbXMgb24gdGhlIGFycmF5LiBTZWUgdGhpcyBbZ2FsbGVyeV0oaHR0cDovL3BsbWltYWdlZ2FsbGVyeS5ibWJvbHN0YWQuY29tLykgb2YgaW50ZXJlc3RpbmcgZXhhbXBsZXMuIEFmZnltZXRyaXgsIGFuZCBvdGhlciBvbGRlciBhcnJheXMgYXJlIHZ1bmVyYWJsZSB0byBzcGF0aWFsIGFydGVmYWN0cyBhcyB0aGUgc2FtZSBwcm9iZSBzZXQgaXMgZm91bmQgaW4gdGhlIHNhbWUgbG9jYXRpb24gb24gZWFjaCBjaGlwLiAKCklmIHlvdSB3YW50IHRvIGxvb2sgYXQgYW4gZXhhbXBsZSBvZiBhIGJhZCBhcnJheSBpbWFnZSwgd2UgY2FuIHVzZSB0aGUgZm9sbG93aW5nIGNvZGU7CgpgYGB7cn0KYmFkIDwtIFJlYWRBZmZ5KGNlbGZpbGUucGF0aCA9ICJlc3Ryb2dlbi8iLGZpbGVuYW1lcz0iYmFkLmNlbCIpCmltYWdlKGJhZCkKYGBgCgpUcnkgb3V0IHNvbWUgaW1hZ2VzIGZvciB0aGlzIGRhdGFzZXQKCmBgYHtyfQpwYXIobWZyb3c9YygyLDQpKQppbWFnZShyYXdbLDFdKQppbWFnZShyYXdbLDJdKQppbWFnZShyYXdbLDNdKQppbWFnZShyYXdbLDRdKQppbWFnZShyYXdbLDVdKQppbWFnZShyYXdbLDZdKQppbWFnZShyYXdbLDddKQppbWFnZShyYXdbLDhdKQpgYGAKCgotIERvIHlvdSBzZWUgYW55IHByb2JsZW1zPwoKSWYgd2UgYXJlIGhhcHB5IHdpdGggdGhlIHF1YWxpdHkgb2YgdGhlIHJhdyBkYXRhIHdlIGNhbiBwcm9jZWVkIHRvIHRoZSBuZXh0IHN0ZXAuIFNvIGZhciBpbiB0aGUgZGF0YSwgd2UgaGF2ZSBtdWx0aXBsZSBwcm9iZXMgd2l0aGluIGEgcHJvYmVzZXQsIGFuZCBhIHBlcmZlY3QgYW5kIG1pc21hdGNoIG1lYXN1cmVtZW50IGZvciBlYWNoIHByb2JlLiBUaGVzZSBhcmUgbm90IHBhcnRpY3VsYXIgY292ZW5pZW50IHZhbHVlcyBmb3Igc3RhdGlzdGljYWwgYW5hbHlzaXMgYXMgd2Ugd291bGQgbGlrZSBhICpzaW5nbGUgbWVhc3VyZW1lbnQqIGZvciBlYWNoIGdlbmUgZm9yIGVhY2ggc2FtcGxlICgvaHlicmlkaXNhdGlvbikuIAoKIyMgU3VtbWFyaXNpbmcgYW5kIE5vcm1hbGlzaW5nIHRoZSBFc3Ryb2dlbiBkYXRhc2V0CgpNYW55IG5vcm1hbGlzYXRpb24gYW5kIHN1bW1hcmlzYXRpb24gbWV0aG9kcyBoYXZlIGJlZW4gZGV2ZWxvcGVkIGZvciBBZmZ5bWV0cml4CmRhdGEuIFRoZXNlIGluY2x1ZGUgTUFTNS4wIGFuZCBQTElFUiB3aGljaCB3ZXJlIGRldmVsb3BlZCBieSBBZmZ5bWV0cml4LCBhbmQgUk1BLApHQy1STUEsIGRDaGlwIGFuZCB2c24gKHRvIG5hbWUgYnV0IGEgZmV3KSB3aGljaCBoYXZlIGJlZW4gZGV2ZWxvcGVkIGJ5IGFjYWRlbWljIHJlc2VhcmNoZXJzLgpNYW55IG9mIHRoZXNlIG1ldGhvZHMgYXJlIGF2YWlsYWJsZSBpbiB0aGUgW2FmZnldKGh0dHA6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy9odG1sL2FmZnkuaHRtbCkgcGFja2FnZS4gRm9yIGEgY29tcGFyaXNvbiBvZiBzb21lIG9mIHRoZXNlCm1ldGhvZHMgYW5kIGFzc2Vzc21lbnQgb2YgdGhlaXIgcGVyZm9ybWFuY2Ugb24gZGlmZmVyZW50IGNvbnRyb2wgZGF0YSBzZXRzLCBzZWUgW0JvbHN0YWQgZXQgYWxdKGh0dHA6Ly9iaW9pbmZvcm1hdGljcy5veGZvcmRqb3VybmFscy5vcmcvY29udGVudC8xOS8yLzE4NS5sb25nKSBvciBbTWlsbGVuYWFyIGV0IGFsXShodHRwOi8vYm1jYmlvaW5mb3JtYXRpY3MuYmlvbWVkY2VudHJhbC5jb20vYXJ0aWNsZXMvMTAuMTE4Ni8xNDcxLTIxMDUtNy0xMzcpLiBJbgp0aGlzIHByYWN0aWNhbCB3ZSB3aWxsIHVzZSB0aGUgKioqUk1BKioqIChSb2J1c3QgTXVsdGljaGlwIEF2ZXJhZ2luZykgbWV0aG9kIGRlc2NyaWJlZCBpbiBbSXJpemFycnkgZXQgYWxdKGh0dHA6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wdWJtZWQvMTI5MjU1MjApLgoKUHJvY2VkdXJlOwoKLSBtb2RlbCBiYXNlZCBiYWNrZ3JvdW5kIGFkanVzdG1lbnQgCi0gZm9sbG93ZWQgYnkgcXVhbnRpbGUgbm9ybWFsaXNhdGlvbiBhbmQgYSAKLSByb2J1c3Qgc3VtbWFyeSBtZXRob2QgKG1lZGlhbiBwb2xpc2gpIG9uIHRoZSBsb2ckXzIkIFBNIGludGVuc2l0aWVzIAotIHRvIG9idGFpbiAqcHJvYmVzZXQgc3VtbWFyeSB2YWx1ZXMqLgoKIyMgTm9ybWFsaXNhdGlvbgoKCi0gV2Ugd2FudCB0byBiZSBvYnNlcnZpbmcgKmJpb2xvZ2ljYWwqIGFuZCBub3QgKnRlY2huaWNhbCogdmFyaWF0aW9uCi0gV2Ugd291bGRuJ3QgZXhwZWN0IHN1Y2ggd2hvbGVzYWxlIGNoYW5nZXMgb24gYSBwZXItc2FtcGxlIGJhc2lzCi0gRWFzeSBvcHRpb24gd291bGQgdG8gc2NhbGUgdmFsdWVzIGZvciBlYWNoIGFycmF5IHRvIG1lZGlhbiBsZXZlbAoKLSAqKldoYXQgd291bGQgaGFwcGVuIGlmIHdlIGhhZCBoeWJyaWRpc2VkIGFsbCB0aGUgKmVzdHJvZ2VuLXRyZWF0ZWQqIHNhbXBsZXMgb24gdGhlIGZpcnN0IGZvdXIgYXJyYXlzLCBhbmQgKnVuLXRyZWF0ZWQqIG9uIHRoZSBsYXN0IGZvdXIqKiAtIENvdWxkIHlvdSBhbmFseXNlIHRoZSBkYXRhPwohW10oaW1hZ2VzL2xpbmVhci1lZmZlY3RzLnBuZykKCgotIEdlbmVzIG9uIGFycmF5IDIgYXJlIG9uIGF2ZXJhZ2UgMi42IGxvd2VyIHRoYW4gdGhlIGdsb2JhbCBtZWRpYW4sIHNvIGFkZCAyLjYgdG8gZWFjaCBnZW5lCi0gR2VuZXMgb24gYXJyYXkgOCBhcmUgb24gYXZlcmFnZSAwLjcgaGlnaGVyIHRoYW4gdGhlIGdsb2JhbCBtZWRpYW4sIHNvIHN1YnRyYWN0IDAuNyBmcm9tIGVhY2ggZ2VuZQotIGV0YwoKCgojIyBOb24tbGluZWFyIGVmZmVjdHMKCkFzIHdlIHNhdyBiZWZvcmUgVGhlICpNQS1wbG90KiBpcyBjb21tb25seS11c2VkIGluIG1pY3JvYXJyYXkgYW5hbHlzaXMgdG8gY29tbW9ubHktdXNlZCB0byB2aXN1YWxpc2UgZGlmZmVyZW5jZXMgYmV0d2VlbiBwYWlycyBvZiBhcnJheXMuIFRoZXNlIHBsb3RzIGNhbiByZXZlYWwgbm9uLWxpbmVhciBlZmZlY3RzIGFuZCBtb3RpdmF0ZSBtb3JlLXNvcGhpc3RpY2F0ZWQgbWV0aG9kcy4gT24gb2xkZXIgYXJyYXkgdGVjaG5vbG9naWVzLCBpdCB3YXMgdHlwaWNhbCB0byBzZWUgYSBiYW5hbmEtc2hhcGVkIHRyZW5kIG9uIHRoZXNlIHBsb3RzLgoKKCoqKm5vdCBvdXIgZGF0YXNldCoqKikKCiFbXShpbWFnZXMvbm9uLWxpbmVhci5wbmcpCgoKIyMgUXVhbnRpbGUgbm9ybWFsaXNhdGlvbgoKVGhpcyBpcyBhcmd1YWJseSB0aGUgbW9zdC1wb3B1bGFyIG5vcm1hbGlzYXRpb24gbWV0aG9kIGF2YWlsYWJsZS4gQ29uc2lkZXIgdGhlIGZvbGxvd2luZyBtYXRyaXggb2YgdmFsdWVzIHRvIGJlIG5vcm1hbGlzZWQKCmBgYHtyIGVjaG89RkFMU0V9CiMgU2V0IGEgc2VlZCB0byBtYWtlIHN1cmUgd2UgZ2V0IHRoZSBzYW1lIG1hdHJpeApzZXQuc2VlZCgiMTUwMjIwMTYiKQpyYXcudmFsdWVzIDwtIHJvdW5kKGRhdGEuZnJhbWUoQXJyYXkxID0gcm5vcm0oNSxtZWFuID0gMiksIEFycmF5MiA9IHJub3JtKDUsbWVhbj0zKSwgQXJyYXkzID0gcm5vcm0oNSxtZWFuPTQpKSwyKQpyb3duYW1lcyhyYXcudmFsdWVzKSA8LSBMRVRURVJTWzE6bnJvdyhyYXcudmFsdWVzKV0KcmF3LnZhbHVlcwpgYGAKCgpgYGB7ciBlY2hvPUZBTFNFfQpyYW5rZWQudmFsdWVzIDwtIGFwcGx5KHJhdy52YWx1ZXMsIDIsIGZ1bmN0aW9uKHgpIHBhc3RlKCJSYW5rIixyYW5rKHgsdGllcy5tZXRob2Q9Im1pbiIpLHNlcD0iIikpCnJhbmtlZC52YWx1ZXMKYGBgCgpTb3J0IGVhY2ggY29sdW1uIFNtYWxsZXN0Li4uTGFyZ2VzdAoKU29ydGVkIGRhdGEKYGBge3J9CmFwcGx5KHJhdy52YWx1ZXMsIDIsc29ydCkKYGBgCgpUaGVuIGNhbGN1bGF0ZSB0YXJnZXQgZGlzdHJpYnV0aW9uIGJ5IGF2ZXJhZ2luZyB0aGUgc29ydGVkIHJvd3MKYGBge3IgZWNobz1GQUxTRX0gCnRhcmdldCA8LSByb3VuZChyb3dNZWFucyhhcHBseShyYXcudmFsdWVzLCAyLHNvcnQpKSwzKQpuYW1lcyh0YXJnZXQpIDwtIHBhc3RlKCJSYW5rIiwgMTpsZW5ndGgodGFyZ2V0KSxzZXA9IiIpCnRhcmdldApgYGAKCkdvIGJhY2sgdG8gdGhlIHJhbmsgbWF0cml4CgpgYGB7ciBlY2hvPUZBTFNFfQpyYW5rZWQudmFsdWVzCgpgYGAKU3Vic3RpdHV0ZSB3aXRoIHZhbHVlcyBmcm9tIHRoZSB0YXJnZXQgZGlzdHJpYnV0aW9uCmBgYHtyIGVjaG89RkFMU0V9CnRhcmdldApgYGAKCmBgYHtyfQpyYW5rZWQudmFsdWVzWywxXSA8LSBnc3ViKCJSYW5rMSIsdGFyZ2V0WyJSYW5rMSJdLHJhbmtlZC52YWx1ZXNbLDFdKQpyYW5rZWQudmFsdWVzCnJhbmtlZC52YWx1ZXNbLDFdIDwtIGdzdWIoIlJhbmsyIix0YXJnZXRbIlJhbmsyIl0scmFua2VkLnZhbHVlc1ssMV0pCnJhbmtlZC52YWx1ZXMKcmFua2VkLnZhbHVlc1ssMV0gPC0gZ3N1YigiUmFuazMiLHRhcmdldFsiUmFuazMiXSxyYW5rZWQudmFsdWVzWywxXSkKcmFua2VkLnZhbHVlcwpyYW5rZWQudmFsdWVzWywxXSA8LSBnc3ViKCJSYW5rNCIsdGFyZ2V0WyJSYW5rNCJdLHJhbmtlZC52YWx1ZXNbLDFdKQpyYW5rZWQudmFsdWVzCnJhbmtlZC52YWx1ZXNbLDFdIDwtIGdzdWIoIlJhbms1Iix0YXJnZXRbIlJhbms1Il0scmFua2VkLnZhbHVlc1ssMV0pCnJhbmtlZC52YWx1ZXMKYGBgCgoKYGBge3J9CmZvcihpIGluIDE6Myl7CnJhbmtlZC52YWx1ZXNbLGldIDwtIGdzdWIoIlJhbmsxIix0YXJnZXRbIlJhbmsxIl0scmFua2VkLnZhbHVlc1ssaV0pCnJhbmtlZC52YWx1ZXNbLGldIDwtIGdzdWIoIlJhbmsyIix0YXJnZXRbIlJhbmsyIl0scmFua2VkLnZhbHVlc1ssaV0pCnJhbmtlZC52YWx1ZXNbLGldIDwtIGdzdWIoIlJhbmszIix0YXJnZXRbIlJhbmszIl0scmFua2VkLnZhbHVlc1ssaV0pCnJhbmtlZC52YWx1ZXNbLGldIDwtIGdzdWIoIlJhbms0Iix0YXJnZXRbIlJhbms0Il0scmFua2VkLnZhbHVlc1ssaV0pCnJhbmtlZC52YWx1ZXNbLGldIDwtIGdzdWIoIlJhbms1Iix0YXJnZXRbIlJhbms1Il0scmFua2VkLnZhbHVlc1ssaV0pCn0KcmFua2VkLnZhbHVlcyA8LSBhcy5kYXRhLmZyYW1lKHJhbmtlZC52YWx1ZXMpCnJvd25hbWVzKHJhbmtlZC52YWx1ZXMpIDwtIHJvd25hbWVzKHJhdy52YWx1ZXMpCgpgYGAKCmBgYHtyfQpyYXcudmFsdWVzCnJhbmtlZC52YWx1ZXMKYGBgCgoKIyNGaW5hbCBDb2RlCgpUaGUgcHJvY2VkdXJlIGNhbiBiZSBlbmNhcHN1bGF0ZWQgaW4gcmVsYXRpdmVseSBmZXcgbGluZXMgb2YgY29kZQoKYGBge3IgZXZhbD1GQUxTRX0KCnJhbmtlZC52YWx1ZXMgPC0gYXBwbHkocmF3LnZhbHVlcywgMiwgZnVuY3Rpb24oeCkgcGFzdGUoIlJhbmsiLAogICAgICByYW5rKHgsdGllcy5tZXRob2Q9Im1pbiIpLHNlcD0iIikpCnRhcmdldCA8LSByb3VuZChyb3dNZWFucyhhcHBseShkZiwgMixzb3J0KSksMykKbmFtZXModGFyZ2V0KSA8LSBwYXN0ZSgiUmFuayIsIDE6bGVuZ3RoKHRhcmdldCksc2VwPSIiKQpmb3IoaSBpbiAxOm5jb2wocmF3LnZhbHVlcykpewogIGZvcihubSBpbiBuYW1lcyh0YXJnZXQpKXsKICAgIHJhbmtlZC52YWx1ZXNbLGldIDwtIGdzdWIobm0sdGFyZ2V0W25tXSxyYW5rZWQudmFsdWVzWyxpXSkgIAogICAgICB9Cn0Kbm9ybSA8LSBhcy5kYXRhLmZyYW1lKHJhbmtlZC52YWx1ZXMpCmBgYAoKCgpXZSBjYW4gdXNlIHRoZSBgbm9ybWFsaXplUXVhbnRpbGVzYCBmdW5jdGlvbiB3aXRoaW4gdGhlIGBsaW1tYWAgcGFja2FnZSB0byBkbyB0aGUgbm9ybWFsaXNhdGlvbi4gCgpgYGB7ciBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KGxpbW1hKQo/bm9ybWFsaXplUXVhbnRpbGVzCmBgYAoKIyMjIENhdmVhdHMKCi0gRGlzdHJpYnV0aW9ucyBvZiBzYW1wbGVzIGFyZSBleHBlY3RlZCB0byBiZSB0aGUgc2FtZQotIE1ham9yaXR5IG9mIGdlbmVzIGRvIG5vdCBjaGFuZ2UgYmV0d2VlbiBncm91cHMKICAgICsgbWlnaHQgYmUgdmlvbGF0ZWQgaWYgeW91IGhhdmUgc2FtcGxlcyB0aGF0IGFyZSBkcmFtYXRpY2FsbHkgYWx0ZXJlZAogICAgKyBlLmcuIGxvdyBudW1iZXIgb2YgZ2VuZXMgaW4gYSBzY3JlZW5pbmcgcGFuZWwgdGhhdCBhcmUgZXhwZWN0ZWQgdG8gY2hhbmdlCiAgICAKIyMgT3RoZXIgbm9ybWFsaXNhdGlvbiBwcm9jZWR1cmVzCgotIGxvZXNzIG9yIHNwbGluZXMKICAgICsgbmVlZCBhIHJlZmVyZW5jZSBvciAiYXZlcmFnZSIgYXJyYXkgdG8gY29tcGFyZSAKICAgICsgZXN0aW1hdGUgdGhlIGN1cnZlIGFuZCB1c2UgdG8gY29ycmVjdCBlYWNoIHBvaW50CiAgICAKCmBgYHtyfQpsaWJyYXJ5KGFmZnkpCj9ub3JtYWxpemUubG9lc3MKYGBgCgoKIyMgUnVubmluZyBSTUEgb24gb3VyIGRhdGFzZXQKClRoZSBhZmZ5IHBhY2thZ2UgcHJvdmlkZXMgbG90cyBvZiBkaWZmZXJlbnQgd2F5cyB0byBwcm9jZXNzIHJhdyBBZmZ5bWV0cmljeCBkYXRhLCBvbmUgb2Ygd2hpY2ggaXMgYW4gaW1wbGVtZW50YXRpb24gb2YgUk1BLiBGb3Igb3RoZXIgbWV0aG9kcywgc2VlIHRoZSBgZXhwcmVzc29gIGZ1bmN0aW9uIG9yIHBhY2thZ2UgKlZpZ25ldHRlKgoKCmBgYHtyIGV2YWw9RkFMU0V9Cj9leHByZXNzbwp2aWduZXR0ZSgiYWZmeSIpCmBgYAoKVGhlIHJlc3VsdCBpcyBhbiBgRXhwcmVzc2lvblNldGAsIHdoaWNoIGlzIGEgdWJpcXVpdG91cyBvYmplY3QgaW4gQmlvb2NvbmR1Y3RvciBmb3Igc3RvcmluZyBoaWdoLXRocm91Z2hwdXQgZGF0YS4gTGF0ZXItb24gaW4gdGhlIGNvdXJzZSB3aWxsIHdlIGltcG9ydCBkYXRhIGZyb20gcHVibGljIHJlcG9zaXRvcmllcywgYW5kIHRoZXNlIGRhdGEgd2lsbCBvZnRlbiBiZSBpbiBhIG5vcm1hbGlzZWQgZm9ybS4KCmBgYHtyfQplc2V0IDwtIHJtYShyYXcpCmVzZXQKYGBgCgpUaGUgYEV4cHJlc3Npb25TZXRgIGlzIGEgY29udmVuaWVudCBvYmplY3QtdHlwZSBmb3Igc3RvcmluZyBtdWx0aXBsZSBoaWdoLWRpbWVuc2lvbmFsIGRhdGEgZnJhbWVzLiBUaGUgc3RydWN0dXJlIG9mIHRoZSBvYmplY3QgaXMgbXVjaCBtb3JlIGNvbXBsaWNhdGVkIHRoYW4gb3RoZXIgdHlwZXMgb2YgZGF0YSB3ZSBoYXZlIHNlZW4gYmVmb3JlLiBJbiBmYWN0IHdlIGRvIG5vdCBuZWVkIHRvIGtub3cgbmVlZCBleGFjdGx5ICpob3cqIHRoZSBvYmplY3QgaXMgY29uc3RydWN0ZWQgaW50ZXJuYWxseS4gVGhlIHBhY2thZ2UgYXV0aG9ycyBoYXZlIHByb3ZpZGVkIGNvbnZlbmllbnQgZnVuY3Rpb25zIHRoYXQgd2lsbCBhbGxvdyB1cyB0byBhY2Nlc3MgdGhlIGRhdGEuIAoKRm9yIGV4YW1wbGUsIGlmIHdlIHdhbnQgdG8gZXh0cmFjdCB0aGUgZXhwcmVzc2lvbiBtZWFzdXJlbWVudHMgdGhlbXNlbHZlcyB0aGUgZnVuY3Rpb24gdG8gdXNlIGlzIGNhbGxlZCBgZXhwcnNgLiBUaGUgcmVzdWx0IHdpbGwgYmUgYSBtYXRyaXggd2l0aCBvbmUgcm93IGZvciBlYWNoIGdlbmUsIGFuZCBvbmUgY29sdW1uIGZvciBlYWNoIHNhbXBsZS4KCmBgYHtyfQpoZWFkKGV4cHJzKGVzZXQpKQpzdW1tYXJ5KGV4cHJzKGVzZXQpKQpgYGAKCllvdSB3aWxsIG5vdGljZSB0aGUgKnJtYSogYWxzbyBpbmNvcnBvcmF0ZXMgYSBsb2ckXzIkIHRyYW5zZm9ybWF0aW9uLiBUaGUgdmFsdWVzIHByZXNlbnQgaW4gdGhlICpjZWwqIGZpbGVzIGFyZSBkZXJpdmVkIGZyb20gcHJvY2Vzc2luZyB0aGUgKlRJRkYqIGltYWdlcyBvZiB0aGUgY2hpcCBzdXJmYWNlLCB3aGljaCBhcmUgb24gdGhlIHNjYWxlIDAgLSAyXjE2LiBIb3dldmVyLCB0aGlzIGlzIG5vdCBhIHZlcnkgY29udmVuaWVudCBzY2FsZSBmb3IgdmlzdWFsaXNhdGlvbiBhbmQgYW5hbHlzaXMgYXMgbW9zdCBvZiB0aGUgb2JzZXJ2YXRpb25zIGFyZSBmb3VuZCBhdCB0aGUgbG93ZXIgZW5kIG9mIHRoZSBzY2FsZSBhbmQgdGhlcmUgaXMgYSBtdWNoIGdyZWF0ZXIgdmFyaWFuY2UgYXQgdGhlIGhpZ2VyIHZhbHVlcy4gV2Ugc2F5IHRoYXQgdGhlIGRhdGEgZXhoaWJpdCBbJ2hldGVyb3NjZWRhc3RpY2l0eSddKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0hldGVyb3NjZWRhc3RpY2l0eSkuIFRvIGFsbGV2aWF0ZSB0aGlzIHdlIGNhbiB1c2UgYSBkYXRhIHRyYW5zZm9ybWF0aW9uIHN1Y2ggYXMgbG9nJF8yJCBhbmQgYWZ0ZXJ3YXJkcyBvdXIgZGF0YSB3aWxsIGJlIGluIHRoZSByYW5nZSAwIHRvIDE2LiBBbm90aGVyIG1ldGhvZCB5b3UgbWF5IGNvbWUgYWNyb3NzIGlzIFt2c25dKGh0dHA6Ly9iaW9pbmZvcm1hdGljcy5veGZvcmRqb3VybmFscy5vcmcvY29udGVudC8xOC9zdXBwbF8xL1M5Ni5sb25nKS4gCgoKYGBge3J9CmJveHBsb3QoZXhwcnMoZXNldCksbGFzPTIpCmBgYAoKCioqKioqKgojIyMgSG93IGNhbiB5b3UgdGVsbCBmcm9tIHRoZSBib3hwbG90IHRoYXQgdGhlc2UgZGF0YSBoYXZlIGJlZW4gbm9ybWFsaXNlZD8KKioqKioqCgpBbiBNQS1wbG90IGNhbiBiZSByZXBlYXRlZCBvbiB0aGUgbm9ybWFsaXNlZCBkYXRhIHRvIHZlcmlmeSB0aGF0IHRoZSBub3JtYWxpc2F0aW9uIHByb2NlZHVyZSBoYXMgYmVlbiBzdWNlc3NmdWwuCgpgYGB7cn0KbXZhLnBhaXJzKGV4cHJzKGVzZXQpWywxOjRdLGxvZy5pdCA9IEZBTFNFLHBsb3QubWV0aG9kPSJzbW9vdGhTY2F0dGVyIikKYGBgCgoKCklmIHdlIGhhdmUgdXNlZCBhICp0YXJnZXRzKiBmaWxlIHRvIHJlYWQgdGhlIHJhdyBkYXRhLCB0aGlzIGluZm9ybWF0aW9uIHdpbGwgc3RvcmVkIGluIHRoZSBzdW1tYXJpc2VkIG9iamVjdC4gQ29tbW9ubHktcmVmZXJyZWQgdG8gYXMgInBoZW5vIGRhdGEiLCB0aGlzIGNhbiByZXRyaWV2ZWQgdXNpbmcgdGhlIGBwRGF0YWAgZnVuY3Rpb24uIEEgbmljZSBwcm9wZXJ0eSBvZiB0aGlzIGRhdGEgZnJhbWUgaXMgdGhhdCB0aGUgKnJvd3MqIGFyZSBhcnJhbmdlZCBpbiB0aGUgc2FtZSBvcmRlciBhcyB0aGUgKmNvbHVtbnMqIG9mIHRoZSBleHByZXNzaW9uIG1hdHJpeC4gaS5lLiBUaGUgZmlyc3QgY29sdW1uIG9mIHRoZSBleHByZXNzaW9uIG1hdHJpeCBpcyBkZXNjcmliZWQgaW4gdGhlIGZpcnN0IHJvdyBvZiB0aGUgcGhlbm8gZGF0YSBtYXRyaXgsIGFuZCBzbyBvbi4gCgpgYGB7cn0KaGVhZChwRGF0YShlc2V0KSkKY29sbmFtZXMoZXhwcnMoZXNldCkpCnJvd25hbWVzKHBEYXRhKGVzZXQpKQpgYGAKCgpDbHVzdGVyaW5nIHRlY2huaXF1ZXMgYW5kIFBDQSB0aGF0IHdlIHdpbGwgbWVldCBsYXRlciBpbiB0aGUgY291cnNlIGNhbiBhbHNvIGluZm9ybSBkZWNpc2lvbnMgYWJvdXQgZXhwZXJpbWVudCBxdWFsaXR5IGJ5IHByb3ZpZGluZyBhIHdheSBvZiB2aXN1YWxpbmcgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHNhbXBsZSBncm91cHMuCgoKIVtdKGltYWdlcy9hZmZ5LWNsdXN0ZXJpbmcucG5nKQoKIVtdKGltYWdlcy9hZmZ5LXBjYS5wbmcpCgoKIyMgQXV0b21hdGVkIHByb2R1Y3Rpb24gb2YgUUMgcGxvdHMKClRoZSBgYXJyYXlRdWFsaXR5TWV0cmljc2AgcGFja2FnZSBpcyBhYmxlIHRvIHByb2R1Y2UgUUEgcGxvdHMgZnJvbSBzZXQgb2YgY2VsIGZpbGVzLCBvciBhIG5vcm1hbGlzZWQgZGF0YXNldC4KCmBgYHtyIGV2YWw9RkFMU0V9CmxpYnJhcnkoYXJyYXlRdWFsaXR5TWV0cmljcykKYXJyYXlRdWFsaXR5TWV0cmljcyhlc2V0KQpgYGAKCiMjIyBUaG91Z2h0cyBvbiBRdWFsaXR5IEFzc2Vzc21lbnQgCgotIEl0IGlzIGRpZmZpY3VsdCB0byBjb21lIHVwIHdpdGggZGVmaW5pdGl2ZSBydWxlcyBhYm91dCB3aGVuIHRvIHJlamVjdCBhIHNhbXBsZSBmcm9tIHRoZSBhbmFseXNpcwotIFRyeSBhbmQga2VlcCBhcyBtdWNoIGluZm9ybWF0aW9uIGZyb20gdGhlIGxhYgogICAgKyBSSU4gKFJOQSBJbnRlZ3JpdHkgTnVtYmVycyksIHR1bW91ciBjb21wb3NpdGlvbgotIElmIHdlIHRyeSBhbmQgcmVqZWN0IHNhbXBsZXMgZm9yIGxvb2tpbmcgZGlmZmVyZW50LCB3ZSBtaWdodCBiaWFzIG91ciByZXN1bHRzIGFuZCBtaXNzIGludGVyZXN0aW5nIGZpbmRpbmdzCi0gSWYgdGhlIG1ham9yaXR5IG9mIG91ciBzYW1wbGVzIGFyZSBwb29yIHF1YWxpdHksIHRoZSBiZXR0ZXIgcXVhbGl0eSBvbmVzIG1pZ2h0IHN0YW5kLW91dCBhcyBvdXRsaWVycyEKLSBUcnkgYW5kIGNvbGxlY3QgYXMgbWFueSBzYW1wbGVzIC8gcmVwbGljYXRlcyBhcyBwb3NzaWJsZSB0byBiZSB0b2xlcmFudCB0byB2YXJpYXRpb24KCiMjIFN1bW1hcnkKCi0gQWZmeSBkYXRhIGNvbWUgaW4gYC5jZWxgIGZpbGVzIHRoYXQgY2FuIGJlIGltcG9ydGVkIHdpdGggdGhlIGBhZmZ5YCBwYWNrYWdlCi0gUUMgY2hlY2tzIG9uIHRoZSByYXcgZGF0YSBpbmNsdWRlOwogICAgKyBjaGVjayB0aGUgY2hpcCBpbWFnZQogICAgKyBwcm9iZS1sZXZlbCBtb2RlbHMKICAgICsgYm94cGxvdHMKLSBBZmZ5IGRhdGEgbmVlZCB0byBiZSBzdW1tYXJpc2VkIGJlZm9yZSBmdXJ0aGVyIGFuYWx5c2lzCiAgICArIGBybWFgIChhbmQgdmFyaWFudHMgdGhlcmVvZikgaXMgbW9zdC1wb3B1bGFyCi0gQWZmeSBkYXRhIGNhbiBiZSBzdW1tYXJpc2VkIGludG8gYSBjb21tb24gQmlvY29uZHVjdG9yIG9iamVjdC10eXBlCiAgICArIFRoZSAiYEV4cHJlc3Npb25TZXRgIgotIFRoZSBgRXhwcmVzc2lvblNldGAsIG9yIGRlcml2YXRpZXMgdGhlcmVvZiwgaXMgdXNlZCB0aHJvdWdob3V0IEJpb2NvbmR1Y3RvciB0byByZXByZXNlbnQgYWxsIHR5cGVzIG9mIGhpZ2gtdGhyb3VnaHB1dCBkYXRhCiAgICArIG1ldGh5bGF0aW9uLCBDaElQLCBSTkEtc2VxCiAgICArIGJhc2ljYWxseSBhbnl0aGluZyB3aGVyZSB5b3UgY2FuIGhhdmUgc29tZSBraW5kIG9mIGdlbm9taWMgbWVhc3VyZSBhcyByb3dzLCBhbmQgc2FtcGxlcyBhcyBjb2x1bW5zCg==